﻿/*  ----------------------------------------------------------------------------
 *  DES-Release 2
 *  ----------------------------------------------------------------------------
 *  File:       SSPIHelper.cs
 *  Author:     nitinkoshy@gmail.com
 *  Source:     http://des.codeplex.com/
 *  ----------------------------------------------------------------------------
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Principal;
using System.Net.Sockets;
using System.Net;
using System.Net.Security;
using DES.Common;

namespace DES.Server.Service.Helpers
{
    public static class SSPIHelper
    {

        enum AuthenticationState { Unknown, Success, Failure } ;

        public static WindowsPrincipal LogonUser(Credential credential)
        {
            string userName, domain, password;
           
            userName = credential.UserName;
            domain = credential.Domain;
            password = credential.Password;

            TcpListener tcpListener = new TcpListener(IPAddress.Loopback, 0);
            tcpListener.Start();

            WindowsIdentity id = null;
            AuthenticationState authState = AuthenticationState.Unknown;

            IAsyncResult serverResult = tcpListener.BeginAcceptTcpClient(delegate(IAsyncResult asyncResult)
            {
                using (NegotiateStream serverSide = new NegotiateStream(
                         tcpListener.EndAcceptTcpClient(asyncResult).GetStream()))
                {
                    try
                    {
                        serverSide.AuthenticateAsServer(CredentialCache.DefaultNetworkCredentials,
                             ProtectionLevel.None, TokenImpersonationLevel.Impersonation);
                        id = (WindowsIdentity)serverSide.RemoteIdentity;
                        authState = AuthenticationState.Success;
                    }
                    catch (Exception)
                    {
                        authState = AuthenticationState.Failure;
                    }
                }
            }, null);


            using (NegotiateStream clientSide = new NegotiateStream(new TcpClient("localhost",
                         ((IPEndPoint)tcpListener.LocalEndpoint).Port).GetStream()))
            {
                try
                {
                    clientSide.AuthenticateAsClient(new NetworkCredential(userName, password, domain),
                             "", ProtectionLevel.None, TokenImpersonationLevel.Impersonation);
                    authState = AuthenticationState.Success;
                }
                catch (Exception)//catch all
                {
                    authState = AuthenticationState.Failure;
                }
            }

            while (authState == AuthenticationState.Unknown) ;

            tcpListener.Stop();
            if (authState == AuthenticationState.Success)
                return new WindowsPrincipal(id);
            else
                return null;
        }
    }
}
